package org.jsola.hr.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.jsola.common.FileKit;
import org.jsola.contract.entity.ContractDO;
import org.jsola.contract.vo.CategoryVO;
import org.jsola.contract.vo.PartySignAccountVO;
import org.jsola.contract.vo.SealVO;
import org.jsola.core.Page;
import org.jsola.exception.ParamException;
import org.jsola.hr.common.ExampleKit;
import org.jsola.hr.common.FileDown;
import org.jsola.hr.common.JunZiQianUtil;
import org.jsola.hr.constant.ContractsStatus;
import org.jsola.hr.constant.HrConstants;
import org.jsola.hr.constant.JunZiQianConstants;
import org.jsola.hr.core.JunZiQianProperties;
import org.jsola.hr.dao.ICompanyContractQuotaDAO;
import org.jsola.hr.dto.CompanyContractQuotaAddDTO;
import org.jsola.hr.dto.CompanyContractQuotaUpdateDTO;
import org.jsola.hr.entity.CompanyContractQuotaDO;
import org.jsola.hr.provider.IContractProviderService;
import org.jsola.hr.query.CompanyContractQuotaQuery;
import org.jsola.hr.service.ICompanyContractQuotaService;
import org.jsola.hr.vo.CompanyContractQuotaVO;
import org.jsola.hr.vo.junziqian.CompanyVariableVO;
import org.jsola.hr.vo.junziqian.NotifyResult;
import org.jsola.hr.vo.junziqian.SignNotifyVO;
import org.jsola.json.JsonKit;
import org.jsola.user.core.TokenUser;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StopWatch;
import tk.mybatis.mapper.entity.Example;

import java.io.File;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;

/**
 * 员工自定义信息关联变量
 *
 * @author zhr
 */
@Slf4j
@Service("hrCompanyContractQuotaServiceImpl")
public class CompanyContractQuotaServiceImpl implements ICompanyContractQuotaService {

    @Autowired
    private ICompanyContractQuotaDAO companyContractQuotaDAO;

    @Autowired
    private JunZiQianProperties junZiQianProperties;

    @Lazy
    @Autowired
    private IContractProviderService contractProviderService;


    @Override
    @Transactional(value = HrConstants.TX, rollbackFor = Exception.class)
    public CompanyContractQuotaVO save(CompanyContractQuotaAddDTO companyContractQuotaAddDTO, TokenUser tokenUser) {
        Example example = new Example(CompanyContractQuotaDO.class);
        example.and()
                .andEqualTo("email", companyContractQuotaAddDTO.getEmail());
        List<CompanyContractQuotaDO> dos = companyContractQuotaDAO.selectByExample(example);
        ParamException.isTrue(CollectionUtils.isEmpty(dos), "邮箱已被占用");

        Example example1 = new Example(CompanyContractQuotaDO.class);
        example1.and()
                .andEqualTo("companyName", companyContractQuotaAddDTO.getCompanyName());
        List<CompanyContractQuotaDO> dos1 = companyContractQuotaDAO.selectByExample(example1);
        ParamException.isTrue(CollectionUtils.isEmpty(dos1), "用工单位已配置，请勿重复处理");

        // 转DO
        CompanyContractQuotaDO companyContractQuotaDO = companyContractQuotaAddDTO.to(CompanyContractQuotaDO.class);
        companyContractQuotaDO.setStatus(0);
        // 保存
        companyContractQuotaDO = save(companyContractQuotaDO, tokenUser.getSiteId(), tokenUser.getUserId());
        sendHttp(companyContractQuotaDO, JunZiQianConstants.URL_COMPANY_CREATE);
        return companyContractQuotaDO.to(CompanyContractQuotaVO.class);
    }

    @Override
    @Transactional(value = HrConstants.TX, rollbackFor = Exception.class)
    public int update(CompanyContractQuotaUpdateDTO companyContractQuotaUpdateDTO, TokenUser tokenUser) {
        Example example = new Example(CompanyContractQuotaDO.class);
        example.and()
                .andEqualTo("email", companyContractQuotaUpdateDTO.getEmail())
                .andNotEqualTo("id", companyContractQuotaUpdateDTO.getId());
        List<CompanyContractQuotaDO> dos = companyContractQuotaDAO.selectByExample(example);
        ParamException.isTrue(CollectionUtils.isEmpty(dos), "邮箱已被占用");

        Example example1 = new Example(CompanyContractQuotaDO.class);
        example1.and()
                .andEqualTo("companyName", companyContractQuotaUpdateDTO.getCompanyName())
                .andNotEqualTo("id", companyContractQuotaUpdateDTO.getId());
        List<CompanyContractQuotaDO> dos1 = companyContractQuotaDAO.selectByExample(example1);
        ParamException.isTrue(CollectionUtils.isEmpty(dos1), "用工单位已配置，请勿重复处理");
        CompanyContractQuotaVO vo = selectById(companyContractQuotaUpdateDTO.getId(), tokenUser.getSiteId());
        ParamException.isFalse(Objects.equals(vo.getStatus(), 0), "审核中无法编辑");

        //转DO
        CompanyContractQuotaDO companyContractQuotaDO = companyContractQuotaUpdateDTO.to(CompanyContractQuotaDO.class);
        companyContractQuotaDO.setOrganizationRegNo(null);
        companyContractQuotaDO.setStatus(vo.getStatus());
        sendHttp(companyContractQuotaDO, JunZiQianConstants.URL_COMPANY_REAPPLY);
        companyContractQuotaDO.setStatus(0);
        //根据主键更新，只更新非null值
        return updateByIdSelective(companyContractQuotaDO, tokenUser.getSiteId(), tokenUser.getUserId());
    }

    /**
     * 组装参数，请求君子签接口
     */
    private void sendHttp(CompanyContractQuotaDO companyContractQuotaDO, String url) {
        url = junZiQianProperties.getServicesUrl() + url;
        CompanyVariableVO vo = new CompanyVariableVO();
        if (Objects.equals(companyContractQuotaDO.getStatus(), 2)) {
            vo.setAuthStatus(0);
        } else {
            vo.setAuthStatus(1);
        }
        vo.setEmailOrMobile(companyContractQuotaDO.getEmail());
        vo.setLegalName(companyContractQuotaDO.getLegalName());
        vo.setName(companyContractQuotaDO.getCompanyName());
        vo.setOrganizationType(companyContractQuotaDO.getOrganizationType());
        vo.setIdentificationType(1);
        vo.setOrganizationRegNo(companyContractQuotaDO.getOrganizationRegNo());
        File file = FileDown.getFile(companyContractQuotaDO.getFileUrl());
        vo.setOrganizationRegImg(file);
        vo.setNotifyUrl(junZiQianProperties.getNotifyUrl());
        JunZiQianUtil.send(vo, junZiQianProperties, url);
        // 删除临时文件
        file.delete();
    }

    @Override
    @Transactional(value = HrConstants.TX, rollbackFor = Exception.class)
    public int deleteByIds(TokenUser tokenUser, String... companyContractQuotaIds) {
        return logicalDeleteByIds(tokenUser.getSiteId(), tokenUser.getUserId(), (Object[]) companyContractQuotaIds);
    }


    @Override
    public CompanyContractQuotaVO selectById(Long companyContractQuotaId, String siteId) {
        CompanyContractQuotaDO companyContractQuotaDO = selectDOById(companyContractQuotaId, siteId);
        if (companyContractQuotaDO == null) {
            return null;
        }
        return companyContractQuotaDO.to(CompanyContractQuotaVO.class);
    }


    @Override
    public List<CompanyContractQuotaVO> select(CompanyContractQuotaQuery companyContractQuotaQuery, String siteId) {
        List<CompanyContractQuotaDO> companyContractQuotaDOList = selectDO(companyContractQuotaQuery, siteId);
        if (CollectionUtils.isEmpty(companyContractQuotaDOList)) {
            return companyContractQuotaDOList == null ? null : new ArrayList<>();
        }
        return companyContractQuotaDOList.stream()
                .map(companyContractQuotaDO -> companyContractQuotaDO.to(CompanyContractQuotaVO.class))
                .collect(Collectors.toList());
    }

    @Override
    public int selectCount(CompanyContractQuotaQuery companyContractQuotaQuery, String siteId) {
        Example example = buildExample(companyContractQuotaQuery, siteId);
        return companyContractQuotaDAO.selectCountByExample(example);
    }

    @Override
    public Page<CompanyContractQuotaVO> selectPage(CompanyContractQuotaQuery companyContractQuotaQuery, String siteId) {
        Example example = buildExample(companyContractQuotaQuery, siteId);
        Page<CompanyContractQuotaDO> page = companyContractQuotaDAO.selectPageByExample(example,
                companyContractQuotaQuery.getPageNo(),
                companyContractQuotaQuery.getPageSize());

        return page.to(CompanyContractQuotaVO.class);
    }

    @Override
    public CompanyContractQuotaDO selectDOById(Long companyContractQuotaId, String siteId) {
        return listById(companyContractQuotaId, siteId);
    }

    @Override
    public List<CompanyContractQuotaDO> selectDO(CompanyContractQuotaQuery companyContractQuotaQuery, String siteId) {
        Example example = buildExample(companyContractQuotaQuery, siteId);
        return companyContractQuotaDAO.selectByExample(example);
    }


    /**
     * 根据查询参数，构建example
     *
     * @param companyContractQuotaQuery 查询参数
     * @param siteId                    所属站点id
     * @return example
     */
    private Example buildExample(CompanyContractQuotaQuery companyContractQuotaQuery, String siteId) {
        Example example = new Example(CompanyContractQuotaDO.class);
        example.and()
                .andEqualTo("valid", true)
                .andEqualTo("siteId", siteId)
                .andEqualTo("status", companyContractQuotaQuery.getStatus());
        if (!CollectionUtils.isEmpty(companyContractQuotaQuery.getCompanyIds())) {
            example.and().andIn("companyId", companyContractQuotaQuery.getCompanyIds());
        }
        // 排序
        ExampleKit.setExampleOrder(example, companyContractQuotaQuery.getOrders());
        return example;
    }

    @Override
    @Transactional(value = HrConstants.TX, rollbackFor = Exception.class)
    public CompanyContractQuotaVO saveOrUpdate(CompanyContractQuotaUpdateDTO companyContractQuotaUpdateDTO, TokenUser tokenUser) {
        CompanyContractQuotaDO companyContractQuotaDO = companyContractQuotaUpdateDTO.to(CompanyContractQuotaDO.class);
        CompanyContractQuotaDO companyContractQuotaDOTmp = selectDOBySiteId(tokenUser.getSiteId());

        if (companyContractQuotaUpdateDTO.getId() != null) {
            //添加判断是否存在
            if (Objects.nonNull(companyContractQuotaDOTmp)) {
                return companyContractQuotaDOTmp.to(CompanyContractQuotaVO.class);
            }
            // 保存
            companyContractQuotaDO = save(companyContractQuotaDO, tokenUser.getSiteId(), tokenUser.getUserId());
            return companyContractQuotaDO.to(CompanyContractQuotaVO.class);
        } else {
            //编辑判断是否存在
            if (Objects.isNull(companyContractQuotaDOTmp)) {
                return null;
            }
            //根据主键更新，只更新非null值
            updateByIdSelective(companyContractQuotaDO, tokenUser.getSiteId(), tokenUser.getUserId());
            return companyContractQuotaDO.to(CompanyContractQuotaVO.class);
        }
    }

    @Override
    public CompanyContractQuotaDO selectDOBySiteId(String siteId) {
        Example example = new Example(CompanyContractQuotaDO.class);
        example.and()
                .andEqualTo("valid", true)
                .andEqualTo("siteId", siteId);
        return companyContractQuotaDAO.selectOneByExample(example);
    }

    @Override
    @Transactional(value = HrConstants.TX, rollbackFor = Exception.class)
    public Object notify(Map<String, String> map) {
        StopWatch stopWatch = new StopWatch("君子签回调");
        stopWatch.start("");
        HashMap<Object, Object> hashMap = new HashMap<>();
        NotifyResult result = new NotifyResult();
        BeanUtil.fillBeanWithMapIgnoreCase(map, result, true);
        log.info("==========君子签回调，参数：{}", JsonKit.toJSONString(result));
        switch (result.getMethod()) {
            case JunZiQianConstants.METHOD_COMPANY: {
                CompanyVariableVO vo = JSON.parseObject(result.getData(), CompanyVariableVO.class);
                String emailOrMobile = vo.getEmailOrMobile();
                CompanyContractQuotaDO quotaDO = selectByEmail(emailOrMobile);
                // 审核状态（1通过2驳回）
                if (Objects.equals(vo.getStatus(), 1)) {
                    quotaDO.setStatus(1);
                    quotaDO.setReason("");
                } else {
                    quotaDO.setStatus(2);
                    quotaDO.setReason(vo.getMsg());
                }
                quotaDO.setGmtModified(new Date());
                updateById(quotaDO);
                break;
            }
            case JunZiQianConstants.METHOD_SIGN: {
                CompletableFuture.runAsync(() -> {

                    StopWatch watch = new StopWatch("君子签合同签约回调");
                    watch.start("校验数据");
                    SignNotifyVO vo = JSON.parseObject(result.getData(), SignNotifyVO.class);
                    // 根据合同编号获取合同信息
                    String applyNo = vo.getApplyNo();
                    ContractDO contractDO = contractProviderService.selectByContractNo(applyNo);
                    ParamException.notNull(contractDO, "合同不存在");
                    watch.stop();

                    if (Objects.equals(vo.getSignStatus(), 1) && Objects.equals(vo.getIdentityType(), 1)) {
                        watch.start("个人签约");
                        if (!Objects.equals(contractDO.getStatus(), ContractsStatus.WAIT_FOR_EMPLOYEES.getValue())) {
                            log.error("数据状态错误--》当前合同状态：{}，实际应为：待员工签署", ContractsStatus.find(contractDO.getStatus()).getDesc());
                            return;
                        }
                        List<PartySignAccountVO> account = contractProviderService.findPartySignAccount(contractDO.getId(), contractDO.getSiteId());
                        PartySignAccountVO accountVO = account.stream().filter(s -> Objects.equals(s.getType(), 1)).findAny().get();
                        // 组装token
                        TokenUser tokenUser = new TokenUser(accountVO.getMemberId(), contractDO.getSiteId());
                        log.info("个人签约完成回调，合同onSuccess，{}", applyNo);
                        byte[] bytes = getBytes(vo.getApplyNo());
                        contractProviderService.personSign(contractDO.getId(), bytes, Boolean.FALSE, tokenUser);
                        watch.stop();
                    } else if (Objects.equals(vo.getSignStatus(), 1) && Objects.equals(vo.getIdentityType(), 12)) {
                        log.info("企业签约完成回调，无需处理，{}", applyNo);
                    } else if (Objects.equals(vo.getSignStatus(), 3)) {
                        watch.start("签约完结");
                        if (!Objects.equals(contractDO.getStatus(), ContractsStatus.WAIT_FOR_COMPANY.getValue())) {
                            log.error("数据状态错误--》当前合同状态：{}，实际应为：待公司签署", ContractsStatus.find(contractDO.getStatus()).getDesc());
                            return;
                        }
                        // 组装token
                        TokenUser tokenUser = new TokenUser(contractDO.getCreateUserId(), contractDO.getSiteId());
                        log.info("全部签约流程结束，合同onComplete，{}", applyNo);
                        byte[] bytes = getBytes(vo.getApplyNo());
                        Long categoryId = contractDO.getCategoryId();
                        CategoryVO categoryVO = contractProviderService.selectCategoryById(categoryId, tokenUser.getSiteId());
                        SealVO sealVO = contractProviderService.selectSealById(categoryVO.getEnterpriseSealId(), tokenUser.getSiteId());
                        contractProviderService.companySign(contractDO.getId(), String.valueOf(sealVO.getOrganizationId()), bytes, Boolean.FALSE, tokenUser);
                        watch.stop();
                    }
                    log.info("签约回调耗时{}", watch.prettyPrint());
                }).exceptionally(e -> {
                    log.error("合同签约回调失败，", e);
                    return null;
                });
                break;
            }
            case JunZiQianConstants.METHOD_FACE: {
                log.info("人脸回调");
                break;
            }
            default:
                log.info("其他回调");
                break;
        }
        hashMap.put("success", true);
        stopWatch.stop();
        log.info("回调耗时{}", stopWatch.prettyPrint());
        return hashMap;
    }

    /**
     * 获取文件字节
     */
    private byte[] getBytes(String applyNo) {
        String url = junZiQianProperties.getServicesUrl() + JunZiQianConstants.URL_CONTRACT_LINK_FILE;
        // 获取下载链接
        Map<String, Object> params = new HashMap<>();
        params.put("applyNo", applyNo);
        String downloadUrl = String.valueOf(JunZiQianUtil.send(params, junZiQianProperties, url).getData());
        // 下载文件
        File file = HttpUtil.downloadFileFromUrl(downloadUrl, FileKit.getSystemTempPath());
        byte[] bytes = FileUtil.readBytes(file);
        file.delete();
        return bytes;
    }

    @Override
    public CompanyContractQuotaDO selectByEmail(String email) {
        Example example = new Example(CompanyContractQuotaDO.class);
        example.and()
                .andEqualTo("valid", true)
                .andEqualTo("email", email);
        return companyContractQuotaDAO.selectOneByExample(example);
    }


}




